feat: add workflow for blast radius api (CM-1328)#4372
Conversation
PR SummaryMedium Risk Overview The route uses a dedicated stricter rate limit (default 5/hour, env-tunable) and interim
Unit tests cover Zod validation, the handler, and the failure helper; root vitest adds a Reviewed by Cursor Bugbot for commit cd4f5b6. Bugbot is set up for automated code reviews on this repo. Configure here. |
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
7cd58ae to
fd4f294
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fd4f294. Configure here.
There was a problem hiding this comment.
Pull request overview
Adds the initial Blast Radius API and Temporal workflow plumbing; analysis currently fails intentionally until the pipeline is implemented.
Changes:
- Adds validated, authenticated, rate-limited job submission.
- Adds shared Temporal types and a dedicated worker.
- Adds tests, OpenAPI documentation, and local/build configuration.
Reviewed changes
Copilot reviewed 16 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
services/libs/types/src/temporal/index.ts |
Exports blast-radius types. |
services/libs/types/src/temporal/blastRadius.ts |
Defines workflow input. |
services/libs/types/src/enums/temporal.ts |
Adds workflow ID. |
services/apps/packages_worker/src/workflows/index.ts |
Exports the workflow. |
services/apps/packages_worker/src/blast-radius/workflows.ts |
Implements the temporary failing workflow. |
services/apps/packages_worker/src/blast-radius/ecosystemSupport.ts |
Builds non-retryable failures. |
services/apps/packages_worker/src/blast-radius/__tests__/ecosystemSupport.test.ts |
Tests failure construction. |
services/apps/packages_worker/src/bin/blast-radius-worker.ts |
Adds worker entrypoint. |
services/apps/packages_worker/package.json |
Adds scripts and types dependency. |
scripts/services/blast-radius-worker.yaml |
Adds local Compose services. |
scripts/builders/packages.env |
Includes the worker image. |
pnpm-lock.yaml |
Updates workspace dependency resolution. |
backend/src/api/public/v1/packages/submitBlastRadiusJob.ts |
Starts jobs and returns 202. |
backend/src/api/public/v1/packages/submitBlastRadiusJob.test.ts |
Tests submission behavior. |
backend/src/api/public/v1/packages/blastRadius.ts |
Defines validation and response types. |
backend/src/api/public/v1/packages/blastRadius.test.ts |
Tests schema and mapping helpers. |
backend/src/api/public/v1/akrites-external/openapi.yaml |
Documents the endpoint. |
backend/src/api/public/v1/akrites-external/index.ts |
Registers auth, limiting, and routing. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 19 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (2)
backend/src/api/public/v1/packages/submitBlastRadiusJob.ts:35
- This starts the workflow through the API's default Temporal client, but
blast-radius-workerpollsCROWD_PACKAGES_TEMPORAL_NAMESPACE. Those namespaces are explicitly separate inbackend/src/db/packagesTemporal.ts:8-11, so in deployed environments this run will remain queued instead of reaching the new worker. Obtain the client withgetPackagesTemporalClient()and start the workflow through it; update the handler test to mock that client.
await req.temporal.workflow.start('analyzeBlastRadius', {
backend/src/api/public/v1/akrites-external/openapi.yaml:388
- The runtime rejects both omitted/null ecosystems and every value except
npm, but this request schema advertisesecosystemas optional and nullable. Generated clients can therefore send requests that are guaranteed to receive 400. Make the field required, non-nullable, and constrain it to the documented allow-list.
ecosystem:
type: string
nullable: true
description: Optional, only meaningful alongside package.
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 19 changed files in this pull request and generated 4 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)
backend/src/api/public/v1/akrites-external/openapi.yaml:422
- This documents an impossible response: requests without
ecosystemare rejected before the handler runs, and accepted responses always echonpm. Removenullable: trueand the sentence claiming it can be null so generated clients match runtime behavior.
ecosystem:
type: string
nullable: true
description: Echoes the request's ecosystem. Null when the request omitted it.
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>

Summary
Adds the first slice of the Blast Radius feature: a
POST /akrites-external/blast-radius/jobsendpoint that accepts a request to analyze the blast radius of an advisory (optionally scoped
to a single package), and an on-demand Temporal workflow (
analyzeBlastRadius, running on a newblast-radius-workertask queue inpackages_worker) that it triggers. There is no reachabilitypipeline yet — every submission is accepted (
202,status: pending), but the workflowimmediately fails with a non-retryable
ECOSYSTEM_NOT_SUPPORTEDerror, since the real analysisisn't implemented. This PR only stands up the request/trigger plumbing end-to-end; the pipeline,
persistence, and poll endpoint land in follow-up PRs.
Changes
POST /akrites-external/blast-radius/jobsendpoint (submitBlastRadiusJob.ts), validatedwith a dedicated Zod schema (
blastRadius.ts); always exactly one job per request (advisory-wideif
packageis omitted).ecosystem === 'npm'is accepted; anything else(including a missing/null ecosystem) is rejected with a
400before the Temporal workflow istriggered, so no workflow run is ever spawned for unsupported ecosystems.
analyzeBlastRadiusinpackages_worker/src/blast-radius/, onits own
blast-radius-workertask queue. It currently has no reachability pipeline — it alwaysthrows a non-retryable
ECOSYSTEM_NOT_SUPPORTEDApplicationFailure(even for npm), built by asmall pure helper (
ecosystemSupport.ts) kept outside the workflow function so it's testablewithout the Temporal workflow sandbox.
everything else at
400) is a request-validation gate; the workflow-layer rejection isunconditional (fires for npm too) because the actual pipeline doesn't exist yet. These will
reconcile once the pipeline lands — not a bug, a deliberate interim state for this PR slice.
ITriggerBlastRadiusAnalysisandTemporalWorkflowId.BLAST_RADIUS_ANALYSISadded to
@crowd/types, mirroring the existingITriggerCSVExportpattern.AKRITES_BLAST_RADIUS_RATE_LIMIT_MAX/
_WINDOW_MS, default 5 req/hour) plus the existingrequireScopes([SCOPES.READ_PACKAGES])check— reusing
READ_PACKAGESas an interim scope until Auth0 issues a dedicatedread:advisoriesscope.blast-radius-workerentrypoint,package.jsondev/start scripts, and local-dev docker-composeservice manifest, following the same pattern as the existing
osv-worker/maven-workerworkers.openapi.yamlupdated to document the new endpoint, including the400for unsupported ecosystem.GETpoll endpoint,7-day result caching, the real reachability pipeline, and creating the
blast-radius-workerKubernetes Deployment needed for actual staging/production rollout (
kubectl set imageonly swapsthe image tag on an existing Deployment — it doesn't create one).
Type of change
JIRA ticket
CM-1328